#ifndef TB_PREDEFINED_HPP__
#define TB_PREDEFINED_HPP__

#if defined(__Linux__)
#  define TB_OS_LINUX
#elif defined(__APPLE__)
#  define TB_OS_MACOSX
#elif defined(_WIN32) || defined(WIN32)
#  define TB_OS_WIN
#else
#  error Unknown platform, please add support in base/predefined.hpp
#endif

#if defined(TB_OS_LINUX) || defined(TB_OS_MACOSX)
#  define TB_OS_POSIX
#endif

#if defined(__cplusplus)
#  if (__cplusplus  < 199711L)
#    error unsupported cplusplus version
#  elif (__cplusplus  >= 199711L)
#    define TB_CXX98_STANDARD
#  elif (__cplusplus >= 201103L || _MSC_VER >= 1800)
#    define TB_CXX11_STANDARD
#    define TB_NO_CXX11_RVALUE_REFERENCES
#  elif (__cplusplus >= 201402L || _MSC_VER >= 1900)
#    define TB_CXX14_STANDARD
#    define TB_NO_CXX11_RVALUE_REFERENCES
#  endif
#endif

#ifndef OVERRITE
#if (__cplusplus >= 201103L || _MSC_VER >= 1800)
#  define OVERRITE override
#else 
#  define OVERRITE
#endif
#endif

#ifndef NOEXCEPT
#if (__cplusplus >= 201103L || _MSC_VER >= 1800)
#  define NOEXCEPT throw()
#else 
#  define NOEXCEPT
#endif
#endif

#if defined(__clang__)
#  define TB_COMPILER_CLANG
#elif defined(__GNUC__)
#  define TB_COMPILER_GCC
#elif defined(__INTEL_COMPILER)
#  define TB_COMPILER_INTEL
#elif defined(_MSC_VER)
#  define TB_COMPILER_MSVC
#  if (_MSC_VER >= 1900)
#    define TB_COMPILER_MSVC150
#  elif (_MSC_VER >= 1800)
#    define TB_COMPILER_MSVC120
#  elif (_MSC_VER >= 1700)
#    define TB_COMPILER_MSVC110
#  elif (_MSC_VER >= 1600)
#    define TB_COMPILER_MSVC100
#  elif (__MSC_VER >= 1500)
#    define TB_COMPILER_MSVC90
#  elif (_MSC_VER >= 1400)
#    define TB_COMPILER_MSVC80
#  elif (_MSC_VER >= 1300)
#    define TB_COMPILER_MSVC70
#  endif
#endif

#if defined(__amd64) || defined(__x86_64) || defined(_M_X64) || \
    defined(_M_AMD64) || defined(__aarch64__) || defined(__ia64__) || \
    defined(_M_IA64)
#  define TB_X86_64
#else 
#  define TB_X86
#endif 

#if defined(__BIG_ENDIAN__) || defined(__ARMEB__) || \
    defined(__THUMBEB__) || defined(__AARCH64EB__) || \
    defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__)
#  define TB_ARCH_ENDIAN_LARGE
#else
#  define TB_ARCH_ENDIAN_LITTLE
#endif

#if defined(DEBUG) || defined(_DEBUG)
# ifdef NDEBUG
#   undef NDEBUG
# endif
# define TB_DEBUG
#else
# ifndef NDEBUG
#   define NDEBUG
# endif
#endif

#ifndef RAPIDJSON_HAS_STDSTRING
#define RAPIDJSON_HAS_STDSTRING 1
#endif

#define TB_NEW(T) new T()
#define TB_NEW_ARG(T,...) new T(__VA_ARGS__)
#define TB_DELETE(P) delete P
#define TB_DELETE_ARRAY(ARR) delete[] ARR
#define TB_MALLOC(SIZE) malloc(SIZE)
#define TB_REALLOC(PTR, SIZE) realloc(PTR, SIZE)
#define TB_FREE(P) free(P)

#define TB_SAFE_DELETE(x) \
	TB_DELETE(x); \
  x = nullptr;

#ifdef TB_DEBUG
#define TB_DEBUG_FLAG "d"
#else 
#define TB_DEBUG_FLAG
#endif

#ifdef TB_OS_WIN
#define TB_LIB_PREFFIX "lib"
#define TB_SHARED_LIB_PREFFIX "dll"
#elif defined(TB_OS_LINUX)
#define TB_LIB_PREFFIX
#define TB_SHARED_LIB_PREFFIX "so"
#elif defined(TB_OS_MACOSX)
#define TB_LIB_PREFFIX
#define TB_SHARED_LIB_PREFFIX "dylib"
#endif

#if defined(TB_OS_WIN)
#define TB_API_EXPORT __declspec(dllexport)
#define TB_API_IMPORT __declspec(dllimport)
#else
#define TB_API_EXPORT
#define TB_API_IMPORT
#endif

#define TB_INLINE inline

#ifndef TB_FORCEINLINE
#	if (_MSC_VER >= 1200)
#		define TB_FORCEINLINE __forceinline
#	else
#		define TB_FORCEINLINE __inline
#	endif
#endif

#ifdef __cplusplus
#define TB_GUARD_EXTERN_C_BEGIN	extern "C" {
#define TB_GUARD_EXTERN_C_END		}
#else
#define TB_GUARD_EXTERN_C_BEGIN
#define TB_GUARD_EXTERN_C_END
#endif

#define TB_NAMESPACE_BEGIN namespace TB {
#define TB_NAMESPACE_END }  //namespace TB
#define TB_NAMESPACE ::TB

#ifdef _T
# undef _T
#endif

# define TB_TEXT_WIDE(x) L ## x

#if defined(UNICODE) || defined(_UNICODE)
# define TB_UNICODE
# define _T(x) TB_TEXT_WIDE(x)
# define TB_TEXT(x) TB_TEXT_WIDE(x)
# define fprintf_ys   fwprintf 
# define strlen_ys    wcslen
#if defined(TB_OS_WIN)
# define scanf_ys wscanf_s
# define fopen_ys _wfopen_s
#else
# define scanf_ys wscanf
# define fopen_ys _wfopen
#endif
#else
# define _T(x) x
# define TB_TEXT(x) x
# define fprintf_ys   fprintf
# define strlen_ys    strlen
#if defined(TB_OS_WIN)
# define scanf_ys scanf_s
# define fopen_ys fopen_s
#else
# define scanf_ys scanf
# define fopen_ys fopen
#endif
#endif



#ifdef _MSC_VER
#  define TB_CALL       __cdecl
#  define TB_NO_INLINE  __declspec(noinline)
#elif defined(__GNUC__) && defined(__i386) && !defined(__INTEL_COMPILER)
#  define TB_CALL       __attribute__((cdecl))
#  define TB_NO_INLINE  __attribute__((noinline))
#else
#  define TB_CALL  
#  define TB_NO_INLINE  __attribute__((noinline))
#endif

// Type detection for wchar_t.
#if defined(TB_OS_WIN)
#  define WCHAR_T_IS_UTF16
#elif defined(TB_OS_POSIX) && defined(TB_COMPILER_GCC) && \
  defined(__WCHAR_MAX__) && \
  (__WCHAR_MAX__ == 0x7fffffff || __WCHAR_MAX__ == 0xffffffff)
#define WCHAR_T_IS_UTF32
#elif defined(TB_OS_POSIX) && defined(TB_COMPILER_GCC) && \
  defined(__WCHAR_MAX__) && \
  (__WCHAR_MAX__ == 0x7fff || __WCHAR_MAX__ == 0xffff)
// On Posix, we'll detect short wchar_t, but projects aren't guaranteed to
// compile in this mode (in particular, Chrome doesn't). This is intended for
// other projects using base who manage their own dependencies and make sure
// short wchar works for them.
#define WCHAR_T_IS_UTF16
#else
#error Please add support for your compiler
#endif

# ifdef __va_copy 
# define ys_va_copy(DEST,SRC) __va_copy((DEST),(SRC)) 
# else 
# define ys_va_copy(DEST, SRC) memcpy((&DEST), (&SRC), sizeof(va_list)) 
# endif 

#if defined(TB_COMPILER_MSVC)
// Macros for suppressing and disabling warnings on MSVC.
//
// Warning numbers are enumerated at:
// http://msdn.microsoft.com/en-us/library/8x5x43k7(VS.80).aspx
//
// The warning pragma:
// http://msdn.microsoft.com/en-us/library/2c8f766e(VS.80).aspx
//
// Using __pragma instead of #pragma inside macros:
// http://msdn.microsoft.com/en-us/library/d9x1s805.aspx
// MSVC_SUPPRESS_WARNING disables warning |n| for the remainder of the line and
// for the next line of the source file.
#define MSVC_SUPPRESS_WARNING(n) __pragma(warning(suppress:n))
// MSVC_PUSH_DISABLE_WARNING pushes |n| onto a stack of warnings to be disabled.
// The warning remains disabled until popped by MSVC_POP_WARNING.
#define MSVC_PUSH_DISABLE_WARNING(n) __pragma(warning(push)) \
  __pragma(warning(disable:n))
// MSVC_PUSH_WARNING_LEVEL pushes |n| as the global warning level.  The level
// remains in effect until popped by MSVC_POP_WARNING().  Use 0 to disable all
// warnings.
#define MSVC_PUSH_WARNING_LEVEL(n) __pragma(warning(push, n))
// Push current warning states.
#define MSVC_PUSH_WARNING() __pragma(warning(push))
// Disable warning |n|
#define MSVC_DISABLE_WARNING(n) __pragma(warning(disable:n))
// Pop effects of innermost MSVC_PUSH_* macro.
#define MSVC_POP_WARNING() __pragma(warning(pop))
#define MSVC_DISABLE_OPTIMIZE() __pragma(optimize("", off))
#define MSVC_ENABLE_OPTIMIZE() __pragma(optimize("", on))
// Allows exporting a class that inherits from a non-exported base class.
// This uses suppress instead of push/pop because the delimiter after the
// declaration (either "," or "{") has to be placed before the pop macro.
//
// Example usage:
// class EXPORT_API Foo : NON_EXPORTED_BASE(public Bar) {
//
// MSVC Compiler warning C4275:
// non dll-interface class 'Bar' used as base for dll-interface class 'Foo'.
// Note that this is intended to be used only when no access to the base class'
// static data is done through derived classes or inline methods. For more info,
// see http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx
#define NON_EXPORTED_BASE(code) MSVC_SUPPRESS_WARNING(4275) \
  code
#else  // Not MSVC
#define MSVC_SUPPRESS_WARNING(n)
#define MSVC_PUSH_DISABLE_WARNING(n)
#define MSVC_PUSH_WARNING_LEVEL(n)
#define MSVC_POP_WARNING()
#define MSVC_DISABLE_OPTIMIZE()
#define MSVC_ENABLE_OPTIMIZE()
#define NON_EXPORTED_BASE(code) code
#endif  // COMPILER_MSVC
// The C++ standard requires that static const members have an out-of-class
// definition (in a single compilation unit), but MSVC chokes on this (when
// language extensions, which are required, are enabled). (You're only likely to
// notice the need for a definition if you take the address of the member or,
// more commonly, pass it to a function that takes it as a reference argument --
// probably an STL function.) This macro makes MSVC do the right thing. See
// http://msdn.microsoft.com/en-us/library/34h23df8(v=vs.100).aspx for more
// information. Use like:
//
// In .h file:
//   struct Foo {
//     static const int kBar = 5;
//   };
//
// In .cc file:
//   STATIC_CONST_MEMBER_DEFINITION const int Foo::kBar;
#if defined(TB_COMPILER_MSVC)
# define STATIC_CONST_MEMBER_DEFINITION __declspec(selectany)
# define TB_WEAK_SYMBOL __declspec(selectany)
#elif defined(TB_COMPILER_GCC)
# define TB_WEAK_SYMBOL __attribute__((weak))
#else
# define STATIC_CONST_MEMBER_DEFINITION
#endif

// Annotate a variable indicating it's ok if the variable is not used.
// (Typically used to silence a compiler warning when the assignment
// is important for some other reason.)
// Use like:
//   int x = ...;
//   ALLOW_UNUSED_LOCAL(x);
#define ALLOW_UNUSED_LOCAL(x) false ? (void)x : (void)0
// Annotate a typedef or function indicating it's ok if it's not used.
// Use like:
//   typedef Foo Bar ALLOW_UNUSED_TYPE;
#if defined(TB_COMPILER_GCC)
#define ALLOW_UNUSED_TYPE __attribute__((unused))
#else
#define ALLOW_UNUSED_TYPE
#endif

// Annotate a function indicating it should not be inlined.
// Use like:
//   NOINLINE void DoStuff() { ... }
#if defined(TB_COMPILER_GCC)
#define NOINLINE __attribute__((noinline))
#elif defined(TB_COMPILER_MSVC)
#define NOINLINE __declspec(noinline)
#else
#define NOINLINE
#endif

// Specify memory alignment for structs, classes, etc.
// Use like:
//   class ALIGNAS(16) MyClass { ... }
//   ALIGNAS(16) int array[4];
#if defined(TB_COMPILER_MSVC )
#define ALIGNAS(byte_alignment) __declspec(align(byte_alignment))
#elif defined(TB_COMPILER_GCC)
#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
#endif

// Return the byte alignment of the given type (available at compile time).  Use
// sizeof(type) prior to checking __alignof to workaround Visual C++ bug:
// http://goo.gl/isH0C
// Use like:
//   ALIGNOF(int32)  // this would be 4
#if defined(TB_COMPILER_MSVC)
#define ALIGNOF(type) (sizeof(type) - sizeof(type) + __alignof(type))
#elif defined(TB_COMPILER_GCC)
#define ALIGNOF(type) __alignof__(type)
#endif

// Annotate a function indicating the caller must examine the return value.
// Use like:
//   int foo() WARN_UNUSED_RESULT;
// To explicitly ignore a result, see |ignore_result()| in <base/basic_types.h>.
#if defined(TB_COMPILER_GCC)
#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#else
#define WARN_UNUSED_RESULT
#endif
// Tell the compiler a function is using a printf-style format string.
// |format_param| is the one-based index of the format string parameter;
// |dots_param| is the one-based index of the "..." parameter.
// For v*printf functions (which take a va_list), pass 0 for dots_param.
// (This is undocumented but matches what the system C headers do.)
#if defined(TB_COMPILER_GCC)
#define PRINTF_FORMAT(format_param, dots_param) \
  __attribute__((format(printf, format_param, dots_param)))
#else
#define PRINTF_FORMAT(format_param, dots_param)
#endif
// WPRINTF_FORMAT is the same, but for wide format strings.
// This doesn't appear to yet be implemented in any compiler.
// See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38308 .
#define WPRINTF_FORMAT(format_param, dots_param)

// Macro useful for writing cross-platform function pointers.
#if !defined(CDECL)
#if defined(TB_OS_WIN)
#define CDECL __cdecl
#else  // defined(TB_OS_WIN)
#define CDECL
#endif  // defined(TB_OS_WIN)
#endif  // !defined(CDECL)

// Macro for hinting that an expression is likely to be false.
#if !defined(UNLIKELY)
#if defined(TB_COMPILER_GCC)
#define UNLIKELY(x) __builtin_expect(!!(x), 0)
#define LIKELY(x) __builtin_expect(!(x), 0)
#else
#define UNLIKELY(x) (x)
#define LIKELY(x) (x)
#endif  // defined(COMPILER_GCC)
#endif  // !defined(UNLIKELY)

#endif //TB_PREDEFINED_HPP__
